package simpledb.index;

import simpledb.common.Database;
import simpledb.common.DbException;
import simpledb.common.Type;
import simpledb.common.Utility;
import simpledb.execution.IndexPredicate;
import simpledb.storage.*;
import simpledb.transaction.TransactionAbortedException;
import simpledb.transaction.TransactionId;
import simpledb.execution.Predicate.Op;

import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.*;
import java.util.concurrent.BlockingQueue;

/**
 * BTreeUtility 是一个辅助工具类，用于生成随机数据、构造测试用的 B+ 树文件和元组。
 *
 * 它主要用于 SimpleDB 的单元测试或功能测试中，帮助开发者快速构建带有指定字段数量、行数和索引结构的数据集。
 */
public class BTreeUtility {

    public static final int MAX_RAND_VALUE = 1 << 16; // 最大随机值（65536）

    /**
     * 将一个 Tuple 对象转换为 Integer 类型的列表。
     *
     * @param tuple 输入的 Tuple
     * @return 包含所有字段整数值的列表
     */
    public static List<Integer> tupleToList(Tuple tuple) {
        List<Integer> list = new ArrayList<>();
        for (int i = 0; i < tuple.getTupleDesc().numFields(); ++i) {
            int value = ((IntField) tuple.getField(i)).getValue();
            list.add(value);
        }
        return list;
    }

    /**
     * 返回一个包含单个 IntField 的 Tuple，并设置默认 RecordId。
     *
     * @param n 字段值
     * @return 新建的 Tuple
     */
    public static Tuple getBTreeTuple(int n) {
        Tuple tup = new Tuple(Utility.getTupleDesc(1));
        tup.setRecordId(new RecordId(new BTreePageId(1, 2, BTreePageId.LEAF), 3));
        tup.setField(0, new IntField(n));
        return tup;
    }

    /**
     * 返回一个根据整型数组构造的 Tuple，并设置默认 RecordId。
     *
     * @param tupdata 整型数组
     * @return 新建的 Tuple
     */
    public static Tuple getBTreeTuple(int[] tupdata) {
        Tuple tup = new Tuple(Utility.getTupleDesc(tupdata.length));
        tup.setRecordId(new RecordId(new BTreePageId(1, 2, BTreePageId.LEAF), 3));
        for (int i = 0; i < tupdata.length; ++i)
            tup.setField(i, new IntField(tupdata[i]));
        return tup;
    }

    /**
     * 返回一个根据整型列表构造的 Tuple，并设置默认 RecordId。
     *
     * @param tupdata 整型列表
     * @return 新建的 Tuple
     */
    public static Tuple getBTreeTuple(List<Integer> tupdata) {
        Tuple tup = new Tuple(Utility.getTupleDesc(tupdata.size()));
        tup.setRecordId(new RecordId(new BTreePageId(1, 2, BTreePageId.LEAF), 3));
        for (int i = 0; i < tupdata.size(); ++i)
            tup.setField(i, new IntField(tupdata.get(i)));
        return tup;
    }

    /**
     * 返回一个每个字段都等于 n 的 Tuple，并设置默认 RecordId。
     *
     * @param n 字段值
     * @param width 字段数量
     * @return 新建的 Tuple
     */
    public static Tuple getBTreeTuple(int n, int width) {
        Tuple tup = new Tuple(Utility.getTupleDesc(width));
        tup.setRecordId(new RecordId(new BTreePageId(1, 2, BTreePageId.LEAF), 3));
        for (int i = 0; i < width; ++i)
            tup.setField(i, new IntField(n));
        return tup;
    }

    /**
     * 返回一个 BTreeEntry 实例，键值为 n，默认表 ID 为 1。
     *
     * @param n 键值
     * @return 新建的 BTreeEntry
     */
    public static BTreeEntry getBTreeEntry(int n) {
        BTreePageId leftChild = new BTreePageId(1, n, BTreePageId.LEAF);
        BTreePageId rightChild = new BTreePageId(1, n + 1, BTreePageId.LEAF);
        BTreeEntry e = new BTreeEntry(new IntField(n), leftChild, rightChild);
        e.setRecordId(new RecordId(new BTreePageId(1, 2, BTreePageId.INTERNAL), 3));
        return e;
    }

    /**
     * 返回一个 BTreeEntry 实例，键值为 n，指定表 ID。
     *
     * @param n 键值
     * @param tableid 表 ID
     * @return 新建的 BTreeEntry
     */
    public static BTreeEntry getBTreeEntry(int n, int tableid) {
        BTreePageId leftChild = new BTreePageId(tableid, n, BTreePageId.LEAF);
        BTreePageId rightChild = new BTreePageId(tableid, n + 1, BTreePageId.LEAF);
        BTreeEntry e = new BTreeEntry(new IntField(n), leftChild, rightChild);
        e.setRecordId(new RecordId(new BTreePageId(tableid, 2, BTreePageId.INTERNAL), 3));
        return e;
    }

    /**
     * 返回一个 BTreeEntry 实例，键值为 key，左子节点编号为 n，右子节点编号为 n+1。
     *
     * @param n 子节点编号
     * @param key 键值
     * @param tableid 表 ID
     * @return 新建的 BTreeEntry
     */
    public static BTreeEntry getBTreeEntry(int n, int key, int tableid) {
        BTreePageId leftChild = new BTreePageId(tableid, n, BTreePageId.LEAF);
        BTreePageId rightChild = new BTreePageId(tableid, n + 1, BTreePageId.LEAF);
        BTreeEntry e = new BTreeEntry(new IntField(key), leftChild, rightChild);
        e.setRecordId(new RecordId(new BTreePageId(tableid, 2, BTreePageId.INTERNAL), 3));
        return e;
    }

    /**
     * 创建一个用于测试的随机 B+ 树文件。
     *
     * @param columns 列数
     * @param rows 行数
     * @param columnSpecification 可选列规格（指定某些列固定值）
     * @param tuples 输出参数：生成的元组列表
     * @param keyField 索引键字段索引
     * @return 生成的 BTreeFile
     */
    public static BTreeFile createRandomBTreeFile(int columns, int rows, Map<Integer, Integer> columnSpecification,
                                                  List<List<Integer>> tuples, int keyField) throws IOException,
                                                                                           DbException,
                                                                                           TransactionAbortedException {
        return createRandomBTreeFile(columns, rows, MAX_RAND_VALUE, columnSpecification, tuples, keyField);
    }

    /**
     * 生成一个随机的 B+ 树文件，用于测试目的。
     *
     * @param columns 列数
     * @param rows 行数
     * @param maxValue 随机值的最大值
     * @param columnSpecification 可选列规格（指定某些列固定值）
     * @param tuples 输出参数：生成的元组列表
     * @param keyField 索引键字段索引
     * @return 生成的 BTreeFile
     */
    public static BTreeFile createRandomBTreeFile(int columns, int rows, int maxValue,
                                                  Map<Integer, Integer> columnSpecification,
                                                  List<List<Integer>> tuples, int keyField) throws IOException,
                                                                                           DbException,
                                                                                           TransactionAbortedException {

        if (tuples != null) {
            tuples.clear();
        } else {
            tuples = new ArrayList<>(rows);
        }

        generateRandomTuples(columns, rows, maxValue, columnSpecification, tuples);

        File hFile = File.createTempFile("table", ".dat");
        hFile.deleteOnExit();

        File bFile = File.createTempFile("table_index", ".dat");
        bFile.deleteOnExit();

        Type[] typeAr = new Type[columns];
        Arrays.fill(typeAr, Type.INT_TYPE);
        return BTreeFileEncoder.convert(tuples, hFile, bFile, BufferPool.getPageSize(), columns, typeAr, ',', keyField);
    }

    /**
     * 生成一组随机的元组用于测试。
     *
     * @param columns 列数
     * @param rows 行数
     * @param maxValue 随机值最大值
     * @param columnSpecification 可选列规格（指定某些列固定值）
     * @param tuples 输出参数：生成的元组列表
     */
    public static void generateRandomTuples(int columns, int rows, int maxValue,
                                            Map<Integer, Integer> columnSpecification, List<List<Integer>> tuples) {
        generateRandomTuples(columns, rows, 0, maxValue, columnSpecification, tuples);
    }

    /**
     * 为测试目的生成一组随机元组。
     *
     * @param columns 列数
     * @param rows 行数
     * @param minValue 每个字段的最小随机值
     * @param maxValue 每个字段的最大随机值
     * @param columnSpecification 可选列规格（某些列固定值）
     * @param tuples 输出参数：生成的元组列表
     */
    public static void generateRandomTuples(int columns, int rows, int minValue, int maxValue,
                                            Map<Integer, Integer> columnSpecification, List<List<Integer>> tuples) {

        Random r = new Random();

        // 填充元组列表
        for (int i = 0; i < rows; ++i) {
            List<Integer> tuple = new ArrayList<>(columns);
            for (int j = 0; j < columns; ++j) {
                // 如果 columnSpecification 存在且指定了该列，则使用指定值
                Integer columnValue = null;
                if (columnSpecification != null)
                    columnValue = columnSpecification.get(j);
                if (columnValue == null) {
                    // 否则生成随机值
                    columnValue = r.nextInt(maxValue - minValue) + minValue;
                }
                tuple.add(columnValue);
            }
            tuples.add(tuple);
        }
    }

    /**
     * 生成一组用于测试的 B+ 树内部节点条目（键 + 子指针）。
     *
     * @param numKeys 要生成的键的数量
     * @param minKey 键的最小值
     * @param maxKey 键的最大值
     * @param minChildPtr 第一个子节点编号
     * @param childPointers 输出参数：子节点编号列表
     * @param keys 输出参数：键值列表
     */
    public static void generateRandomEntries(int numKeys, int minKey, int maxKey, int minChildPtr,
                                             List<Integer> childPointers, List<Integer> keys) {

        Random r = new Random();

        // 填充键值和子节点编号
        int child = minChildPtr;
        for (int i = 0; i < numKeys; ++i) {
            keys.add(r.nextInt(maxKey - minKey) + minKey);
            childPointers.add(child);
            ++child;
        }

        // 最后一个额外的子节点编号
        childPointers.add(child);
    }

    /**
     * 生成一组随机的 Tuple 对象用于测试。
     *
     * @param columns 列数
     * @param rows 行数
     * @param min 字段最小值
     * @param max 字段最大值
     * @return 随机生成的 Tuple 列表
     */
    public static List<Tuple> generateRandomTuples(int columns, int rows, int min, int max) {
        List<List<Integer>> tuples = new ArrayList<>(rows);
        generateRandomTuples(columns, rows, min, max, null, tuples);

        List<Tuple> tupleList = new ArrayList<>();
        for (List<Integer> tup : tuples) {
            tupleList.add(getBTreeTuple(tup)); // 将整型列表转换为 Tuple
        }
        return tupleList;
    }

    /**
     * 生成一组用于测试的 BTreeEntry 实例。
     *
     * @param numKeys 键的数量
     * @param tableid 表 ID
     * @param childPageCategory 子页面类型（LEAF 或 INTERNAL）
     * @param minKey 键最小值
     * @param maxKey 键最大值
     * @param minChildPtr 第一个子节点编号
     * @return BTreeEntry 列表
     */
    public static List<BTreeEntry> generateRandomEntries(int numKeys, int tableid, int childPageCategory, int minKey,
                                                         int maxKey, int minChildPtr) {
        List<Integer> keys = new ArrayList<>(numKeys);
        List<Integer> childPointers = new ArrayList<>(numKeys + 1);
        generateRandomEntries(numKeys, minKey, maxKey, minChildPtr, childPointers, keys);
        Collections.sort(keys); // 确保键是有序的

        List<BTreeEntry> entryList = new ArrayList<>();
        for (int i = 0; i < numKeys; ++i) {
            entryList.add(new BTreeEntry(new IntField(keys.get(i)), new BTreePageId(tableid, childPointers.get(i),
                childPageCategory), new BTreePageId(tableid, childPointers.get(i + 1), childPageCategory)));
        }
        return entryList;
    }

    /**
     * 计算指定列数下一页可以容纳多少个元组。
     *
     * @param columns 每个元组的列数
     * @return 每页最多容纳的元组数量
     */
    public static int getNumTuplesPerPage(int columns) {
        int bytesPerTuple = Type.INT_TYPE.getLen() * columns * 8;
        return (BufferPool.getPageSize() * 8 - 3 * BTreeLeafPage.INDEX_SIZE * 8) / (bytesPerTuple + 1);
    }

    /**
     * 创建一个用于测试的随机叶子页。
     *
     * @param pid 页面 ID
     * @param columns 每个元组的列数
     * @param keyField 键字段索引
     * @param min 元组字段最小值
     * @param max 元组字段最大值
     * @return 构造好的叶子页对象
     * @throws IOException IO 异常
     */
    public static BTreeLeafPage createRandomLeafPage(BTreePageId pid, int columns, int keyField, int min, int max)
                                                                                                                  throws IOException {
        int tuplesPerPage = getNumTuplesPerPage(columns);
        return createRandomLeafPage(pid, columns, keyField, tuplesPerPage, min, max);
    }

    /**
     * 创建一个指定元组数量的随机叶子页。
     *
     * @param pid 页面 ID
     * @param columns 每个元组的列数
     * @param keyField 键字段索引
     * @param numTuples 插入的元组数量
     * @param min 元组字段最小值
     * @param max 元组字段最大值
     * @return 构造好的叶子页对象
     * @throws IOException IO 异常
     */
    public static BTreeLeafPage createRandomLeafPage(BTreePageId pid, int columns, int keyField, int numTuples,
                                                     int min, int max) throws IOException {
        Type[] typeAr = new Type[columns];
        Arrays.fill(typeAr, Type.INT_TYPE);
        byte[] data = BTreeFileEncoder.convertToLeafPage(
            BTreeUtility.generateRandomTuples(columns, numTuples, min, max), BufferPool.getPageSize(), columns, typeAr,
            keyField);
        return new BTreeLeafPage(pid, data, keyField);
    }

    /**
     * 计算一页可以容纳的 B+ 树内部节点条目数量。
     *
     * @return 每页最多容纳的条目数量
     */
    public static int getNumEntriesPerPage() {
        int nentrybytes = Type.INT_TYPE.getLen() + BTreeInternalPage.INDEX_SIZE;
        int internalpointerbytes = 2 * BTreeLeafPage.INDEX_SIZE + 1;
        return (BufferPool.getPageSize() * 8 - internalpointerbytes * 8 - 1) / (nentrybytes * 8 + 1);
    }

    /**
     * 创建一个用于测试的随机内部节点页。
     *
     * @param pid 页面 ID
     * @param keyField 键字段索引
     * @param childPageCategory 子节点类型（LEAF 或 INTERNAL）
     * @param minKey 键最小值
     * @param maxKey 键最大值
     * @param minChildPtr 第一个子节点编号
     * @return 构造好的内部页对象
     * @throws IOException IO 异常
     */
    public static BTreeInternalPage createRandomInternalPage(BTreePageId pid, int keyField, int childPageCategory,
                                                             int minKey, int maxKey, int minChildPtr)
                                                                                                     throws IOException {
        int entriesPerPage = getNumEntriesPerPage();
        return createRandomInternalPage(pid, keyField, childPageCategory, entriesPerPage, minKey, maxKey, minChildPtr);
    }

    /**
     * 创建一个指定键数量的随机内部节点页。
     *
     * @param pid 页面 ID
     * @param keyField 键字段索引
     * @param childPageCategory 子节点类型（LEAF 或 INTERNAL）
     * @param numKeys 插入的键数量
     * @param minKey 键最小值
     * @param maxKey 键最大值
     * @param minChildPtr 第一个子节点编号
     * @return 构造好的内部页对象
     * @throws IOException IO 异常
     */
    public static BTreeInternalPage createRandomInternalPage(BTreePageId pid, int keyField, int childPageCategory,
                                                             int numKeys, int minKey, int maxKey, int minChildPtr)
                                                                                                                  throws IOException {
        byte[] data = BTreeFileEncoder.convertToInternalPage(BTreeUtility.generateRandomEntries(numKeys,
            pid.getTableId(), childPageCategory, minKey, maxKey, minChildPtr), BufferPool.getPageSize(), Type.INT_TYPE,
            childPageCategory);
        return new BTreeInternalPage(pid, data, keyField);
    }

    /**
     * 创建一个*非随机*的 B+ 树文件，用于测试。
     *
     * @param columns 列的数量
     * @param rows 行数
     * @param columnSpecification 可选列规格（某些列固定值，其他自动生成）
     * @param tuples 输出参数：生成的元组列表（可传入已存在的 List）
     * @param keyField 键字段索引
     * @return 构造好的 BTreeFile 对象
     * @throws IOException IO 异常
     * @throws DbException 数据库异常
     * @throws TransactionAbortedException 事务中止异常
     */
    public static BTreeFile createBTreeFile(int columns, int rows, Map<Integer, Integer> columnSpecification,
                                            List<List<Integer>> tuples, int keyField) throws IOException, DbException,
                                                                                     TransactionAbortedException {
        if (tuples != null) {
            tuples.clear();
        } else {
            tuples = new ArrayList<>(rows);
        }

        // 填充元组列表
        for (int i = 0; i < rows; ++i) {
            List<Integer> tuple = new ArrayList<>(columns);
            for (int j = 0; j < columns; ++j) {
                // 如果 columnSpecification 存在且指定了该列，则使用指定值
                Integer columnValue = null;
                if (columnSpecification != null)
                    columnValue = columnSpecification.get(j);
                if (columnValue == null) {
                    // 否则按公式 (i + 1) * (j + 1) 生成非随机值
                    columnValue = (i + 1) * (j + 1);
                }
                tuple.add(columnValue);
            }
            tuples.add(tuple);
        }

        // 创建临时文件以存储表数据和索引文件
        File hFile = File.createTempFile("table", ".dat");
        hFile.deleteOnExit();

        File bFile = File.createTempFile("table_index", ".dat");
        bFile.deleteOnExit();

        // 设置所有字段为 INT 类型
        Type[] typeAr = new Type[columns];
        Arrays.fill(typeAr, Type.INT_TYPE);

        // 将元组转换为 B+ 树文件格式并写入磁盘
        return BTreeFileEncoder.convert(tuples, hFile, bFile, BufferPool.getPageSize(), columns, typeAr, ',', keyField);
    }

    /**
     * 打开一个 BTreeFile，并将其添加到数据库目录中。
     *
     * @param cols 表的列数
     * @param f 存储表的文件位置
     * @param keyField 键字段索引
     * @return 打开的 BTreeFile 实例
     */
    public static BTreeFile openBTreeFile(int cols, File f, int keyField) {
        // 创建 TupleDesc 和 BTreeFile 实例
        TupleDesc td = Utility.getTupleDesc(cols);
        BTreeFile bf = new BTreeFile(f, keyField, td);

        // 添加进数据库目录
        Database.getCatalog().addTable(bf, UUID.randomUUID().toString());
        return bf;
    }

    /**
     * 打开一个 BTreeFile，并为其列设置特定前缀名后添加到目录中。
     *
     * @param cols 表的列数
     * @param colPrefix 列名前缀（如 "col"）
     * @param f 文件路径
     * @param keyField 键字段索引
     * @return 打开的 BTreeFile 实例
     */
    public static BTreeFile openBTreeFile(int cols, String colPrefix, File f, int keyField) {
        // 使用带列名前缀的 TupleDesc
        TupleDesc td = Utility.getTupleDesc(cols, colPrefix);
        BTreeFile bf = new BTreeFile(f, keyField, td);
        Database.getCatalog().addTable(bf, UUID.randomUUID().toString());
        return bf;
    }

    /**
     * 创建一个空的 B+ 树文件（不包含任何数据），如果文件已存在则覆盖。
     * 该表将被添加到 Catalog 中，列类型为 IntField，键字段为 keyField。
     *
     * @param path 文件路径
     * @param cols 列数量
     * @param keyField 键字段索引
     * @return 创建好的 BTreeFile 实例
     * @throws IOException IO 异常
     */
    public static BTreeFile createEmptyBTreeFile(String path, int cols, int keyField) throws IOException {
        File f = new File(path);
        // 清空文件内容（或创建新文件）
        FileOutputStream fos = new FileOutputStream(f);
        fos.write(new byte[0]);
        fos.close();

        return openBTreeFile(cols, f, keyField);
    }

    /**
     * 创建一个具有指定页数的空 B+ 树文件（包括根页面和若干空页面）。
     *
     * @param path 文件路径
     * @param cols 列数
     * @param keyField 键字段索引
     * @param pages 页面数量（不含根页面）
     * @return 创建好的 BTreeFile 实例
     * @throws IOException IO 异常
     */
    public static BTreeFile createEmptyBTreeFile(String path, int cols, int keyField, int pages) throws IOException {
        File f = new File(path);
        BufferedOutputStream bw = new BufferedOutputStream(new FileOutputStream(f, true));

        // 写入空的 RootPtrPage 数据
        byte[] emptyRootPtrData = BTreeRootPtrPage.createEmptyPageData();
        byte[] emptyPageData = BTreePage.createEmptyPageData();

        bw.write(emptyRootPtrData); // 第一页是 root pointer page
        for (int i = 0; i < pages; ++i) {
            bw.write(emptyPageData); // 接下来是多个空页面
        }
        bw.close();

        return openBTreeFile(cols, f, keyField);
    }

    /**
     * 线程安全的辅助类，尝试在新线程中插入元组到 B+ 树文件中。
     *
     * @return 启动后的 Thread 实例，可用于控制插入行为
     */
    public static class BTreeWriter extends Thread {

        final TransactionId tid;    // 事务 ID
        final BTreeFile     bf;     // 要插入的目标 BTreeFile
        final int           item;   // 要插入的元组主键值
        final int           count;  // 插入次数
        boolean             success; // 是否成功插入
        Exception           error;  // 出现的错误（如有）
        final Object        slock;  // 成功标志锁
        final Object        elock;  // 错误标志锁

        /**
         * 构造函数
         * @param tid 在哪个事务下插入
         * @param bf 目标 BTreeFile
         * @param item 元组主键值
         * @param count 插入次数
         */
        public BTreeWriter(TransactionId tid, BTreeFile bf, int item, int count) {
            this.tid = tid;
            this.bf = bf;
            this.item = item;
            this.count = count;
            this.success = false;
            this.error = null;
            this.slock = new Object();
            this.elock = new Object();
        }

        @Override
        public void run() {
            try {
                int c = 0;
                while (c < count) {
                    // 创建元组
                    Tuple t = BTreeUtility.getBTreeTuple(item, 2);
                    Database.getBufferPool().insertTuple(tid, bf.getId(), t);

                    // 使用 IndexPredicate 查找插入结果
                    IndexPredicate ipred = new IndexPredicate(Op.EQUALS, t.getField(bf.keyField()));
                    DbFileIterator it = bf.indexIterator(tid, ipred);
                    it.open();
                    c = 0;
                    while (it.hasNext()) {
                        it.next();
                        c++;
                    }
                    it.close();
                }

                // 标记插入成功
                synchronized (slock) {
                    success = true;
                }
            } catch (Exception e) {
                e.printStackTrace();
                synchronized (elock) {
                    error = e;
                }

                Database.getBufferPool().transactionComplete(tid, false);
            }
        }

        /**
         * 检查是否插入成功
         * @return true 表示成功
         */
        public boolean succeeded() {
            synchronized (slock) {
                return success;
            }
        }

        /**
         * 获取发生的异常（如有）
         * @return 出现的异常
         */
        public Exception getError() {
            synchronized (elock) {
                return error;
            }
        }
    }

    /**
     * 辅助类，在新线程中搜索一个或多个元组。
     *
     * @return 启动后的 Thread 实例，可用于控制查找行为
     */
    static class BTreeReader extends Thread {

        final TransactionId tid;  // 执行查找的事务 ID
        final BTreeFile     bf;   // 要查找的目标 BTreeFile
        final Field         f;    // 要查找的字段（作为查询条件）
        final int           count; // 预期找到的元组数量
        boolean             found; // 是否找到了足够的元组
        Exception           error; // 出现的错误（如有）
        final Object        slock; // 成功标志锁
        final Object        elock; // 错误标志锁

        /**
         * 构造函数
         * @param tid 在哪个事务下进行查找
         * @param bf 目标 BTreeFile
         * @param f 查找字段（用作等值匹配）
         * @param count 需要找到的元组数量
         */
        public BTreeReader(TransactionId tid, BTreeFile bf, Field f, int count) {
            this.tid = tid;
            this.bf = bf;
            this.f = f;
            this.count = count;
            this.found = false;
            this.error = null;
            this.slock = new Object();
            this.elock = new Object();
        }

        @Override
        public void run() {
            try {
                while (true) {
                    // 创建等值查找谓词
                    IndexPredicate ipred = new IndexPredicate(Op.EQUALS, f);
                    // 获取索引迭代器
                    DbFileIterator it = bf.indexIterator(tid, ipred);
                    it.open();
                    int c = 0;
                    // 遍历结果集
                    while (it.hasNext()) {
                        it.next();
                        c++;
                    }
                    it.close();

                    // 如果找到足够多的元组，标记为成功
                    if (c >= count) {
                        synchronized (slock) {
                            found = true;
                        }
                        break; // 结束循环
                    }
                }

            } catch (Exception e) {
                e.printStackTrace();
                synchronized (elock) {
                    error = e;
                }

                // 提交事务失败
                Database.getBufferPool().transactionComplete(tid, false);
            }
        }

        /**
         * 检查是否成功找到所需数量的元组
         * @return true 表示成功
         */
        public boolean found() {
            synchronized (slock) {
                return found;
            }
        }

        /**
         * 获取发生的异常（如有）
         * @return 出现的异常
         */
        public Exception getError() {
            synchronized (elock) {
                return error;
            }
        }
    }

    /**
     * 辅助类，在新线程中尝试插入一个元组。
     *
     * @return 启动后的 Thread 实例，可用于控制插入行为
     */
    public static class BTreeInserter extends Thread {

        TransactionId                tid;           // 当前事务 ID
        BTreeFile                    bf;            // 插入目标 BTreeFile
        int[]                        tupdata;       // 元组数据数组
        BlockingQueue<List<Integer>> insertedTuples; // 插入成功的元组列表
        boolean                      success;       // 是否插入成功
        Exception                    error;         // 异常信息
        Object                       slock;         // 成功标志锁
        Object                       elock;         // 错误标志锁

        /**
         * 构造函数
         * @param bf 插入的目标 BTreeFile
         * @param tupdata 要插入的元组数据（int 数组）
         * @param insertedTuples 成功插入的元组队列
         */
        public BTreeInserter(BTreeFile bf, int[] tupdata, BlockingQueue<List<Integer>> insertedTuples) {
            init(bf, tupdata, insertedTuples);
        }

        @Override
        public void run() {
            try {
                // 创建元组
                Tuple t = BTreeUtility.getBTreeTuple(tupdata);
                // 插入到缓冲池中
                Database.getBufferPool().insertTuple(tid, bf.getId(), t);
                // 提交事务
                Database.getBufferPool().transactionComplete(tid);

                // 将插入成功的元组加入队列
                List<Integer> tuple = tupleToList(t);
                insertedTuples.put(tuple);

                // 标记插入成功
                synchronized (slock) {
                    success = true;
                }
            } catch (Exception e) {
                if (!(e instanceof TransactionAbortedException)) {
                    e.printStackTrace(); // 打印非事务中断的异常
                }
                synchronized (elock) {
                    error = e;
                }

                // 回滚事务
                Database.getBufferPool().transactionComplete(tid, false);
            }
        }

        /**
         * 初始化方法，供构造函数和 rerun 方法调用
         */
        private void init(BTreeFile bf, int[] tupdata, BlockingQueue<List<Integer>> insertedTuples) {
            this.tid = new TransactionId();
            this.bf = bf;
            this.tupdata = tupdata;
            this.insertedTuples = insertedTuples;
            this.success = false;
            this.error = null;
            this.slock = new Object();
            this.elock = new Object();
        }

        /**
         * 重新运行插入操作的方法
         */
        public void rerun(BTreeFile bf, int[] tupdata, BlockingQueue<List<Integer>> insertedTuples) {
            init(bf, tupdata, insertedTuples);
            run();
        }

        /**
         * 检查插入操作是否成功
         * @return true 表示插入成功
         */
        public boolean succeeded() {
            synchronized (slock) {
                return success;
            }
        }

        /**
         * 获取在插入过程中发生的异常（如有）
         * @return 出现的异常对象；如果没有则返回 null
         */
        public Exception getError() {
            synchronized (elock) {
                return error;
            }
        }
    }

    /**
     * 辅助类，在新线程中尝试删除一个或多个元组。
     *
     * @return 启动后的 Thread 实例，可用于控制删除行为
     */
    public static class BTreeDeleter extends Thread {

        TransactionId                tid;           // 当前事务 ID
        BTreeFile                    bf;            // 要删除的目标 BTreeFile
        BlockingQueue<List<Integer>> insertedTuples; // 插入成功的元组队列（用于删除）
        List<Integer>                tuple;         // 当前要删除的元组
        boolean                      success;       // 是否删除成功
        Exception                    error;         // 异常信息
        Object                       slock;         // 成功标志锁
        Object                       elock;         // 错误标志锁

        /**
         * 构造函数
         * @param bf 要从中删除元组的目标 BTreeFile
         * @param insertedTuples 包含已插入元组的阻塞队列（用于取出并删除）
         */
        public BTreeDeleter(BTreeFile bf, BlockingQueue<List<Integer>> insertedTuples) {
            init(bf, insertedTuples);
        }

        @Override
        public void run() {
            try {
                // 从队列中取出一个元组
                tuple = insertedTuples.take();

                // 检查元组字段数量是否匹配
                if (bf.getTupleDesc().numFields() != tuple.size()) {
                    throw new DbException("元组描述与数据不匹配");
                }

                // 获取主键字段值作为查找条件
                IntField key = new IntField(tuple.get(bf.keyField()));
                IndexPredicate ipred = new IndexPredicate(Op.EQUALS, key);

                // 获取索引迭代器进行查找
                DbFileIterator it = bf.indexIterator(tid, ipred);
                it.open();

                // 遍历结果集，找到完全匹配的元组进行删除
                while (it.hasNext()) {
                    Tuple t = it.next();
                    if (tupleToList(t).equals(tuple)) {
                        Database.getBufferPool().deleteTuple(tid, t); // 删除元组
                        break;
                    }
                }

                it.close(); // 关闭迭代器
                Database.getBufferPool().transactionComplete(tid); // 提交事务

                // 标记删除成功
                synchronized (slock) {
                    success = true;
                }

            } catch (Exception e) {
                if (!(e instanceof TransactionAbortedException)) {
                    e.printStackTrace(); // 打印非事务中断的异常
                }

                synchronized (elock) {
                    error = e;
                }

                try {
                    // 如果删除失败，把元组重新放回队列以便重试
                    insertedTuples.put(tuple);
                    Database.getBufferPool().transactionComplete(tid, false); // 回滚事务
                } catch (InterruptedException e2) {
                    e2.printStackTrace();
                }
            }
        }

        /**
         * 初始化方法，供构造函数和 rerun 方法调用
         */
        private void init(BTreeFile bf, BlockingQueue<List<Integer>> insertedTuples) {
            this.tid = new TransactionId();
            this.bf = bf;
            this.insertedTuples = insertedTuples;
            this.success = false;
            this.error = null;
            this.slock = new Object();
            this.elock = new Object();
        }

        /**
         * 重新运行删除操作的方法
         */
        public void rerun(BTreeFile bf, BlockingQueue<List<Integer>> insertedTuples) {
            init(bf, insertedTuples);
            run();
        }

        /**
         * 检查删除操作是否成功
         * @return true 表示删除成功
         */
        public boolean succeeded() {
            synchronized (slock) {
                return success;
            }
        }

        /**
         * 获取在删除过程中发生的异常（如有）
         * @return 出现的异常对象；如果没有则返回 null
         */
        public Exception getError() {
            synchronized (elock) {
                return error;
            }
        }
    }
}
